package IC.LIR;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import sun.org.mozilla.javascript.internal.ast.IfStatement;

import IC.BinaryOps;
import IC.AST.*;
import IC.SymbolTable.BlockSymbolTable;
import IC.SymbolTable.ClassSymbolTable;
import IC.SymbolTable.GlobalSymbolTable;
import IC.SymbolTable.SemanticError;
import IC.Visitors.Checker;


public class TranslationVisitor implements PropagatingVisitor<Integer,String>{
	  protected GlobalSymbolTable global;
      
	  //constructor
      public TranslationVisitor(GlobalSymbolTable global){
              this.global = global;
      }

	// string literals map, each element literal string is mapped to the format 'str<i>'
    private Map<String,String> stringLiterals = new HashMap<String,String>();
	private int labelCount=0;
	private int whileCount=0;
	private int stringCount=0;
	private int arrayIndexRegIndex=-1; 
	private boolean b=false;
	String currClassName="";
	String mainMethod="";
	String currField="";
	String currVar="";
	int currFieldOffset=-1;
	
	private String runTime=
		 "# Runtime checks:\n" +
         "__checkNullRef:\n" +
         "Move a,Rc1\n" +
         "Compare 0,Rc1\n" +
         "JumpTrue __checkNullRef_err\n" +
         "Return 9999\n" +
         "__checkNullRef_err:\n" +
         "Library __println(str_null_ref),Rdummy\n" +
         "Jump _error_exit\n\n" +
        
         "__checkArrayAccess:\n" +
         "Move a,Rc1\n" +
         "Move i,Rc2\n" +
         "ArrayLength Rc1,Rc1\n" +
         "Compare Rc1,Rc2\n" +
         "JumpGE __checkArrayAccess_err\n" +
         "Compare 0,Rc2\n" +
         "JumpL __checkArrayAccess_err\n" +
         "Return 9999\n" +
         "__checkArrayAccess_err:\n" +
         "Library __println(str_array_access),Rdummy\n" +
         "Jump _error_exit\n\n" +
        
         "__checkSize:\n" +
         "Move n,Rc1\n" +
         "Compare 0,Rc1\n" +
         "JumpL __checkSize_err\n" +
         "Return 9999\n" +
         "__checkSize_err:\n" +
         "Library __println(str_size),Rdummy\n" +
         "Jump _error_exit\n\n" +
        
         "__checkZero:\n" +
         "Move b,Rc1\n" +
         "Compare 0,Rc1\n" +
         "JumpTrue __checkZero_err\n" +
         "Return 9999\n" +
         "__checkZero_err:\n" +
         "Library __println(str_zero),Rdummy\n" +
         "Jump _error_exit\n\n";
	
	private Map<String,ClassLayout> layoutsList = new HashMap<String,ClassLayout>();
	private List<String> methodsList = new ArrayList<String>();
	private List<String> classDispatchTable= new ArrayList<String>();
	
	public String visit(Program program, Integer context) throws SemanticError {
		String trans="";
		ClassLayout cl;
		for(ICClass c: program.getClasses()){
			
			//check if Library. if so skip it
			if (c.getName().equals("Library")) continue;
			
			// check if has super class and use appropriate constructor	
			if (c.hasSuperClass()){
				cl = new ClassLayout(c, layoutsList.get(c.getSuperClassName()));
			} else {
				cl = new ClassLayout(c);
			}	
			// insert to classLayouts
			layoutsList.put(c.getName(), cl);
			classDispatchTable.add(cl.getDispatchTable());
		}
		
		for(ICClass c: program.getClasses()){
			if (!c.getName().equals("Library"))
				trans+=c.accept(this, 0);
		}
		  String lirBuffer = "";
          
          //insert all string literals
          lirBuffer += "# string literals\n";
          //insert error messages strings
          lirBuffer += "str_null_ref: \"Runtime Error: Null pointer dereference!\"\n";
          lirBuffer += "str_array_access: \"Runtime Error: Array index out of bounds!\"\n";
          lirBuffer += "str_size: \"Runtime Error: Array allocation with negative array size!\"\n";
          lirBuffer += "str_zero: \"Runtime Error: Division by zero!\"\n";
         
          for (String strLiteral: this.stringLiterals.keySet()){
                  lirBuffer += stringLiterals.get(strLiteral)+": \""+strLiteral+"\"\n";
          }
          lirBuffer += "\n";
         
          //insert class dispatch tables
          lirBuffer += "# class dispatch tables\n";
          for (String classDisTab: this.classDispatchTable){
                  lirBuffer += classDisTab+"\n";
          }
          lirBuffer += "\n";
         
          //insert all methods
          //insert runtime check methods
          lirBuffer+=runTime;
          lirBuffer += "# methods\n";
          
         
         trans=lirBuffer+trans;
         
          //insert error exit label
          trans += "\n_error_exit:\n";
		
		
		

		
		return trans;
}

	public String visit(ICClass icClass, Integer context) throws SemanticError {
		currClassName = icClass.getName();
        String trans="";
   
        // recursive calls to methods
        for(Method m: icClass.getMethods()){
               trans+= m.accept(this,0);
        }
       	return trans;
	}

	public String visit(Field field, Integer context) throws SemanticError {
		return "";
	}

	
	public String visit(VirtualMethod method, Integer context)
			throws SemanticError {
		String trans= "_";
        trans +=currClassName;
        trans += "_"+method.getName()+":\n";
               
        for (Statement s: method.getStatements()){
        	trans += s.accept(this,0);
        }
        
        // if method returns void concatenate a "return 9999"
        if(method.getType().getName().equals("void")){
        	trans+= "Return 9999\n";
        } 
        methodsList.add(trans);
        return trans;
     	}

	public String visit(StaticMethod method, Integer context)
			throws SemanticError {
		String trans="_";
		  // create method label
        boolean isMain = method.getName().equals("main") &&
        				 method.getType().getName().equals("void") &&
        				 method.getFormals().size() == 1 &&
        				 method.getFormals().get(0).getType().getArrName().equals("string[]");

        
        trans += isMain ? "ic" : currClassName;
        trans+= "_"+method.getName()+":\n";
        
        for (Statement s: method.getStatements()){
                trans += s.accept(this,0);
        }
        // if method returns void (but not main), concatenate a "return 9999"
        if(method.getType().getName().equals("void") && !isMain){
                trans += "Return 9999\n";
        }
       
        if (isMain){
                mainMethod = trans;
        } else {
                methodsList.add(trans);
        }
        
		return trans;
	}

	public String visit(LibraryMethod method, Integer context)
			throws SemanticError {
		return "";
	}

	public String visit(Formal formal, Integer context) throws SemanticError {
		return "";
	}
	
	public String visit(PrimitiveType type, Integer context)
			throws SemanticError {
		return "";
	}

	public String visit(UserType type, Integer context) throws SemanticError {
		return "";
	}

	public String visit(Assignment assignment, Integer context) throws SemanticError {
		String trans="\n# assignment of line "+assignment.getLine()+"\n";
		trans+=assignment.getAssignment().accept(this,context);
		trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
		b=false;
		trans+=assignment.getVariable().accept(this, context+1);
		trans+=getMove()+" R"+context+","+getReg(context+1)+"\n";
		if (b){trans+="Move R"+(context+1)+","+currVar+"\n";b=false;}
		return trans;
	}


	public String visit(CallStatement callStatement, Integer context)
			throws SemanticError {
		return callStatement.getCall().accept(this, context);
	}


	public String visit(Return returnStatement, Integer context)
			throws SemanticError {
		String trans = "";
		if (returnStatement.hasValue()){
			
			trans+= returnStatement.getValue().accept(this, context);
			trans += "Return R"+context+"\n";
		} else {
			trans += "Return 9999\n";
		}
		return trans;
	}

	public String visit(If ifStatement, Integer context) throws SemanticError {		
		String trans = "";
        String falseLabel = "_false_label"+labelCount;
        String endLabel = "_end_label"+(labelCount++);
       
        trans += ifStatement.getCondition().accept(this, context);
        trans += "Compare 0,R"+context+"\n";
        if (ifStatement.hasElse()) 
        	trans += "JumpTrue "+falseLabel+"\n";
        else 
        	trans += "JumpTrue "+endLabel+"\n";
        trans += ifStatement.getOperation().accept(this, context);
       
        if (ifStatement.hasElse()){
            trans += "Jump "+endLabel+"\n";
            trans += falseLabel+":\n";
            trans += ifStatement.getElseOperation().accept(this, context);
         }
        trans += endLabel+":\n";
       
        return  trans;
	}

	public String visit(While whileStatement, Integer context)
			throws SemanticError {
		String trans="\n# whilestatement of line "+whileStatement.getLine()+"\n";
		String testLabel="_test_label"+labelCount;
		String endLabel="_end_label"+labelCount;
		int prevWhile=whileCount;
		whileCount=labelCount++;
		
		
		trans+=testLabel+":\n";
		trans+=whileStatement.getCondition().accept(this, context);
		trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
		b=false;
		trans+="Compare 0,R"+context+"\n";
		trans+="JumpTrue "+endLabel+"\n";
		trans+=whileStatement.getOperation().accept(this, context+1);
		trans+="Jump "+testLabel+"\n";
		trans+=endLabel+":\n";
		
		whileCount=prevWhile;
		return trans;
	}

	public String visit(Break breakStatement, Integer context)
			throws SemanticError {
		return "Jump _end_label"+whileCount+"\n";
	}

	public String visit(Continue continueStatement, Integer context)
			throws SemanticError {
		return "Jump _test_label"+whileCount+"\n";
	}

	public String visit(StatementsBlock statementsBlock, Integer context)
			throws SemanticError {
		String trans="";
		for (Statement s: statementsBlock.getStatements()){
			trans+=s.accept(this, context);
		}
		return trans;
	}

	
	
	public String visit(LocalVariable localVariable, Integer context)
			throws SemanticError {
		String trans="";
		if (localVariable.hasInitValue()){
			trans=localVariable.getInitValue().accept(this,context);
			trans += "Move R"+context+","+localVariable.getName()+"\n";
		}
		return trans;
	}

	
	public String visit(VariableLocation location, Integer context)
			throws SemanticError {
		//needs to be deleted
		String trans="";
		currVar=location.getName();
		
		if (location.isExternal()){
			// must be field!
			currField=location.getName();
			trans+=location.getLocation().accept(this, context);
			// get the ClassLayout for the location
			IC.TypeTable.Type locationClassType =
				(IC.TypeTable.Type)location.getLocation().accept(new IC.Visitors.Checker(global));
			b=false;
			ClassLayout locationClassLayout = layoutsList.get(locationClassType.getName());
            // get the field offset for the variable
			Field f = getFieldASTNodeRec(locationClassLayout.getICClass(), location.getName());
			int fieldOffset = locationClassLayout.getFieldOffset(f);
			currFieldOffset=fieldOffset;
			trans += "StaticCall __checkNullRef(a=R"+context+"),Rdummy\n";
		}
		
		else{
			 trans+="Move "+location.getName()+",R"+context+"\n";
			 b=true;
		}
		
		return trans;
	}

	public String visit(ArrayLocation location, Integer context)
			throws SemanticError {
		String trans="\n#array Location in line : "+location.getLine()+"\n";
		trans += location.getIndex().accept(this, context+1);
		trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
		b=false;
		trans += location.getArray().accept(this, context);
		trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+(context)+"\n");
		b=false;
		trans += "StaticCall __" +
				"checkNullRef(a=R"+context+"),Rdummy\n";
		trans += "StaticCall __checkArrayAccess(a=R"+context+",i=R"+(context+1)+"),Rdummy\n";
	 	arrayIndexRegIndex=context+1;
		b=false;
	 	return trans;
	}

	public String visit(StaticCall call, Integer context) throws SemanticError {
		int i;		
		String trans="\n#static call to "+call.getName()+"\n";

		 i=0;
		 for (Expression arg: call.getArguments()){
             trans+= arg.accept(this, context+i);
             trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			 b=false;
           
             i++;
     }
		
		
		  if (call.getClassName().equals("Library")){
              return trans+libraryCallVisit(call,context);
      }
		
		ClassLayout cl=layoutsList.get(call.getClassName());
		
		Method m=cl.getMethodByName(call.getName());
		trans+="StaticCall _"+((ClassSymbolTable)m.getEnclosingScope()).getId()+"_"+m.getName()+"(";
		
		for (i=0;i<call.getArguments().size();i++)
			trans+=m.getFormals().get(i).getName()+"=R"+(context+i)+",";
			
		if (trans.endsWith(",")) 
			trans=trans.substring(0, trans.length()-1);
		trans+="),R"+context+"\n";
		
		return trans;
		
		
	}

	public String visit(VirtualCall call, Integer context) throws SemanticError {
		String trans="\n#virtual call to "+call.getName()+"\n";
		String className="";
		int i=1;
		
		if (call.isExternal())
			trans+=call.getLocation().accept(this, context);
		else
			trans+="Move this,R"+context+"\n";
		
		 for (Expression arg: call.getArguments()){
            trans+= arg.accept(this, context+i);
            trans+=b ? "" : (getMove()+" "+getReg(context+i)+",R"+(context+i)+"\n");
    		b=false;
            i++;
		}
		  
		
		trans+="VirtualCall R"+context+".";

		if (!call.isExternal()){  
			className=currClassName;
		}
		else{
			  className = ((IC.TypeTable.ClassType) call.getLocation().accept(new Checker(global))).getName();
			//find the class where the function is located in
		}
		
		ClassLayout cl=layoutsList.get(className);
		Method m=cl.getMethodByName(call.getName());
		trans+=cl.getMethodOffset(m)+"(";
		for (i=0;i<call.getArguments().size();i++){
			trans+=m.getFormals().get(i).getName()+"=R"+(context+i+1)+",";
		}
		if (trans.endsWith(",")) 
			trans=trans.substring(0, trans.length()-1);
		trans+="),R"+context+"\n";
		b=true;
		return trans;
	}


	public String visit(This thisExpression, Integer context)
			throws SemanticError {
		return "Move this,R"+context+"\n";
	}

	
	public String visit(NewClass newClass, Integer context)
			throws SemanticError {
		String trans="\nnew Class "+newClass.getName()+"\n";//needs to be deleted
		ClassLayout thisClassLayout = layoutsList.get(newClass.getName());
		trans = "Library __allocateObject("+thisClassLayout.getAllocSize()+"),R"+context+"\n";
		trans += "MoveField _DV_"+thisClassLayout.getClassName()+",R"+context+".0\n";
		return trans;
	}


	public String visit(NewArray newArray, Integer context)throws SemanticError {
		String trans="\n#New array in line "+newArray.getLine() +" \n";
		trans+=newArray.getSize().accept(this, context);
		trans+="Mul 4,R"+context+"\n";
		trans+="StaticCall __checkSize(s=R"+context+"),Rdummy\n";
		trans+="Library __allocateArray(R"+context+"),R"+context+"\n";
		
		return trans;
	}

	public String visit(Length length, Integer context) throws SemanticError {
		String trans="";
		trans+=length.getArray().accept(this, context);
		trans += "StaticCall __checkNullRef(a=R"+context+"),Rdummy\n";
		trans += "ArrayLength R"+context+",R"+context+"\n";
		return trans;
	}

	public String visit(MathBinaryOp binaryOp, Integer context)
		throws SemanticError {
		String trans = "\n#Math binary Op  :  "+binaryOp.getOperator().getOperatorString()+"\n";
         
         // recursive call to operands
		trans += binaryOp.getFirstOperand().accept(this, context);
		trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
		b=false;
		trans += binaryOp.getSecondOperand().accept(this, context+1);
		trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
		b=false;
		switch (binaryOp.getOperator()){
		case PLUS:
			IC.TypeTable.Type operandsType = (IC.TypeTable.Type) binaryOp.getFirstOperand().accept(new Checker(global));
			if (operandsType.isSubTypeOf(IC.TypeTable.TypeTable.getMapPrimitiveTypes().get("int"))){
				trans += "Add R"+(context+1)+",R"+context+"\n";
				b=true;
			} else { 
				trans += "Library __stringCat(R"+context+",R"+(context+1)+"),R"+context+"\n";
			}
			break;
		case MINUS:
			trans += "Sub R"+(context+1)+",R"+context+"\n";
			break;
		case MULTIPLY:
			trans += "Mul R"+(context+1)+",R"+context+"\n";
			break;
		case DIVIDE:
			// check division by zero
			trans += "StaticCall __checkZero(b=R"+(context+1)+"),Rdummy\n";
			trans += "Div R"+(context+1)+",R"+context+"\n";
      		break;
		case MOD:
			trans += "Mod R"+(context+1)+",R"+context+"\n";
			break;
          }
         
          return 	trans;
		
	}

	public String visit(LogicalBinaryOp binaryOp, Integer context)
			throws SemanticError {
		String trueLabel = "_true_label"+labelCount;
		//String falseLabel = "_false_label"+labelCount;
		String endLabel = "_end_label"+(labelCount++);

		String trans = "\n#Logic binary Op  :  "+binaryOp.getOperator().getOperatorString()+"\n";    
  
		
		switch (binaryOp.getOperator()){
		case EQUAL:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpTrue "+trueLabel+"\n";
			break;
		case NEQUAL:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpFalse "+trueLabel+"\n";
			break;
		case GT:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpG "+trueLabel+"\n";
			break;
		case GTE:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpGE "+trueLabel+"\n";
			break;
		case LT:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpL "+trueLabel+"\n";
			break;
		case LTE:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Compare R"+context+",R"+(context+1)+"\n";
			trans += "JumpLE "+trueLabel+"\n";
			break;
		case LAND:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += "Compare 0,R"+context+"\n";
			trans += "JumpTrue "+endLabel+"\n";
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "And R"+(context+1)+",R"+context+"\n";
			 trans += "Jump "+endLabel+"\n";
			break;
		case LOR:
			trans += binaryOp.getFirstOperand().accept(this, context);
			trans+=b ? "" : (getMove()+" "+getReg(context)+",R"+context+"\n");
			b=false;
			trans += "Compare 1,R"+context+"\n";
			trans += "JumpTrue "+endLabel+"\n";
			trans += binaryOp.getSecondOperand().accept(this, context+1);
			trans+=b ? "" : (getMove()+" "+getReg(context+1)+",R"+(context+1)+"\n");
			b=false;
			trans += "Or R"+(context+1)+",R"+context+"\n";
			trans += "Jump "+endLabel+"\n";
			break;        
         }
         trans += "Move 0,R"+context+"\n";
         trans += "Jump "+endLabel+"\n";
         trans += trueLabel+":\n";
         trans += "Move 1,R"+context+"\n";
         trans += endLabel+":\n";

		return trans;
	}

	public String visit(MathUnaryOp unaryOp, Integer context)
			throws SemanticError {
		String trans = "";	
		trans += unaryOp.getOperand().accept(this, context);
		trans += "Neg R"+context+"\n";  	
		return trans;
	}

	public String visit(LogicalUnaryOp unaryOp, Integer context)
			throws SemanticError {
		String trans = "";
		String trueLabel="_true_lable"+labelCount;
		String endLabel="_end_lable"+(labelCount++);
		trans += unaryOp.getOperand().accept(this, context);
		trans += "Compare 0,R"+context+"\n";
		trans += "JumpTrue "+trueLabel;
		trans += "Move 0,R"+context+"\n";
		trans += trueLabel+":\n";
		trans += "Move 1,R"+context+"\n";
		trans += endLabel+":\n";
		
		return trans;
	}

	public String visit(Literal literal, Integer context) throws SemanticError {
        //needs to bedeleted
		String trans = "";
        switch (literal.getType()){
        case STRING:
                String strVal = ((String) literal.getValue()).replaceAll("\n", "\\\\n");
                if (!stringLiterals.containsKey(strVal))
                        stringLiterals.put(strVal, "str"+(stringCount++));
                trans +="Move "+stringLiterals.get(strVal)+",R"+context+"\n";
                b=true;
                break;
        case INTEGER:
                trans += "Move "+literal.getValue().toString()+",R"+context+"\n";
                b=true;
                break;
        case NULL:
                trans += "Move 0,R"+context+"\n"; //should be changed to ""
                b=true;
                break;
        case FALSE:
                trans += "Move 0,R"+context+"\n";
                b=true;
                break;
        case TRUE:
        		trans += "Move 1,R"+context+"\n";
        		b=true;
        }
       
        return trans;
	
	}

	public String visit(ExpressionBlock expressionBlock, Integer context)
			throws SemanticError {
		return expressionBlock.getExpression().accept(this, context);
		 
	}
    
	private String libraryCallVisit(Call call,int d){
		String trans = "";
         trans += "Library __"+call.getName()+"(";
         // iterate over values (registers)
         for(int i = 0; i < call.getArguments().size(); i++){
                 trans += "R"+(i+d)+",";
         }
         // remove last comma
         if (trans.endsWith(",")) 
        	 trans = trans.substring(0, trans.length()-1);
         trans += "),R"+d+"\n";
        
		return trans;
	}
	
    private Field getFieldASTNodeRec(ICClass icClass, String fieldName){
    	for(Field f: icClass.getFields()){
                if (f.getName().equals(fieldName))
                        return f;
        }
        if (icClass.hasSuperClass()){
        	
        	ClassLayout cl=layoutsList.get(icClass.getSuperClassName());
                return getFieldASTNodeRec(cl.getICClass(), fieldName);
        } else
                System.err.println("*** ERROR: could not find superclass when should be\n");
        return null;
}
    
    
    private String getMove(){
    	if (currField!="")
    		return "MoveField";
    	if (arrayIndexRegIndex!=-1)
			return "MoveArray";
    	return "Move";
    }
    
    private String getReg(int context){
    	
    	if (currField!=""){
    		currField="";
    		return "R"+context+"."+currFieldOffset;
    		}
    	if (arrayIndexRegIndex!=-1){
    		arrayIndexRegIndex=-1;
			return "R"+(context)+"[R"+(context+1)+"]";
    	}
    	return "R"+context;
    }
    
 
    
    
   
}